﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Threading;
using System.Timers;
using System.Windows;
using System.Windows.Threading;
using BitsDownloadMgr.Interop;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
using VMDS.Business.Entities;
using VMDS.Business.Processes;
using VMDS.GUIClient.Helper;
using VMDS.GUIClient.Model;
using VMDS.GUIClient.ServiceReference;
using VMDS.Settings;

namespace VMDS.GUIClient.ViewModels
{
    class TaskEventArgs
    {
        public TaskDataPack TaskInfo;
    }

    internal delegate void TaskEventHandler(object sender, TaskEventArgs e);

    [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
    internal class Listener:IClientServiceContractCallback
    {
        public void OnTaskChanged(TaskDataPack task)
        {
            if (OnChanged!=null)OnChanged(this,new TaskEventArgs(){TaskInfo = task});
        }

        public void OnTaskAdded(TaskDataPack task)
        {
            if (OnAdded!=null)OnAdded(this,new TaskEventArgs(){TaskInfo = task});
        }

        public void OnTaskCmpleted(TaskDataPack task)
        {
            if (OnCompleted!=null)OnCompleted(this,new TaskEventArgs(){TaskInfo = task});
        }

        public event TaskEventHandler OnAdded;
        public event TaskEventHandler OnChanged;
        public event TaskEventHandler OnCompleted;

    }

    class Operation:BaseViewModel
    {
        public int VmOrOsID { get; set; }
        public bool IsVm { get; set; }
        
        private string _name;
        public string Name 
        {
            get { return _name; } 
            set { _name = value;}
        }

        private int _p;
        public int Progress
        {
            get { return _p; }
            set { _p = value;OnPropertyChanged(()=>Progress); }
        }

        private string _oper;
        public string CurrentOperation
        {
            get { return _oper; }
            set { _oper = value;OnPropertyChanged(()=>CurrentOperation);}
        }
        public Guid Id { get; set; }

    }

    class OperationsViewModel:BaseViewModel
    {
        private ClientServiceContractClient client;
        private Listener listener;
      
        public void Setup(VM vm)
        {
          if (client==null) InitClient();
            if (client.State==CommunicationState.Faulted) InitClient();
            client.Deploy(vm.Id);
           
            var op = new Operation()
            {
                CurrentOperation = "Ожидание ответа..",
                Name = vm.Name,
                VmOrOsID = vm.Id
            }; 
            Operations.Add(op);

        }

        private ObservableCollection<Operation> _ops=new ObservableCollection<Operation>();
        public ObservableCollection<Operation> Operations
        {
            get { return _ops; }
            set { _ops = value;
                OnPropertyChanged(() => Operations);
            }
        }

        
       void InitClient()
       {
           client = new ClientServiceContractClient(new InstanceContext(listener), new NetTcpBinding(),
                                                        new EndpointAddress(ServiceLocator.CsAddress));
           client.Register();
       }

        private Thread thread;
        public OperationsViewModel()
        {
            Operations.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Operations_CollectionChanged);
            listener = new Listener();
            thread = Thread.CurrentThread;
            listener.OnAdded += new TaskEventHandler(listener_OnAdded);
            listener.OnChanged += new TaskEventHandler(listener_OnChanged);
            listener.OnCompleted += new TaskEventHandler(listener_OnCompleted);
            try
            {
                InitClient();
                var tasks = client.GetCurrentOperations();
                foreach (var task in tasks)
                {
                    var op = new Operation()
                                 {
                                     CurrentOperation = task.CurrentOperation,
                                     Id = task.ID,
                                     Progress = task.CurrentProgress
                                 };
                    Operations.Add(op);
                }
            }
            catch
            {
                ShowMessageBox("Сведения об операциях недоступны");
            }

        }

        void listener_OnCompleted(object sender, TaskEventArgs e)
        {
            var op = Operations.SingleOrDefault(x => x.Id == e.TaskInfo.ID);
            if (op!=null)
                Dispatcher.FromThread(thread).
                   Invoke(new Action(() => Operations.Remove(op)), DispatcherPriority.Render);
           
        }

        void listener_OnChanged(object sender, TaskEventArgs e)
        {
            var op = Operations.SingleOrDefault(x => x.Id == e.TaskInfo.ID);
            var task = e.TaskInfo;
            op.CurrentOperation = task.CurrentOperation;
            op.Id = task.ID;
            op.Progress = task.CurrentProgress;
            op.Name = task.VmName;
            op.VmOrOsID = task.VmID;

        }

        void listener_OnAdded(object sender, TaskEventArgs e)
        {
            var task = e.TaskInfo;

            var op = Operations.SingleOrDefault(x => x.VmOrOsID == task.VmID);
            if (op != null) Dispatcher.FromThread(thread).
                    Invoke(new Action(() => Operations.Remove(op)), DispatcherPriority.Render);
                op = new Operation()
            {
                CurrentOperation = task.CurrentOperation,
                Id = task.ID,
                Progress = task.CurrentProgress, 
                Name = task.VmName,
                VmOrOsID = task.VmID

            }; 
            Dispatcher.FromThread(thread).
                   Invoke(new Action(() => Operations.Add(op)), DispatcherPriority.Render);
            
        }

        void Operations_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            SayToMainView();
            OnPropertyChanged(()=>Operations);
        }

        public bool IsBusy(VM vm)
        {
            var isinops = Operations.Any(op => (op.VmOrOsID == vm.Id));
            return  isinops;
        }

      /*
        int GetProgress(CopyJob job)
        {

            var result = 0;
            if (job.BytesTotal!=0)
                result= (int) ((job.BytesTransferred*100)/job.BytesTotal);
            return result;
        }*/
       

        public int GetCount()
        {
            return Operations.Count;
           
        }

        void SayToMainView()
        {
              if (CrossWindowConnector.MainView != null)
                ((MainWindowViewModel)CrossWindowConnector.MainView).TaskLibButtonText = "Текущие операции (" + Operations.Count + ")";
                
        }
        private static OperationsViewModel _inst;
        public static OperationsViewModel Instance { 
            get { return _inst ?? (_inst = new OperationsViewModel()); }
        }
         
    }
}
